#include <QDebug>
#include <QPluginLoader>
#include "PluginManager.h"

PluginManager::PluginManager(QStringList pluginPaths,
                             QObject *parent) :
   QObject(parent),
   thePluginPaths(pluginPaths)
{
   if(thePluginPaths.isEmpty())
   {
      qCritical() << "No plugin paths provided";
   }
}

void PluginManager::startPlugins()
{
   foreach(QString path, thePluginPaths)
   {
      loadPlugin(path);
   }

   emit signalStartService();
}

void PluginManager::stopPlugins()
{
   emit signalStopService();

   foreach(QString path, thePluginPaths)
   {
      unloadPlugin(path);
   }
}

void PluginManager::loadPlugin(QString path)
{
   QPluginLoader loader(path);
   IPlugin *interface = qobject_cast<IPlugin*>(loader.instance());

   // Plugin loaded successfully
   if(loader.isLoaded())
   {
      Plugin *plugin = interface->getPlugin();
      QThread *thread = new QThread();

      thePlugins.insert(plugin, thread);

      // Connect to plugin
      connect(this, SIGNAL(signalStartService()), plugin, SLOT(slotStartService()));
      connect(this, SIGNAL(signalStopService()), plugin, SLOT(slotStopService()), Qt::BlockingQueuedConnection);

      // Connect rest of core to plugin
      emit signalRegisterPlugin(plugin);

      // Start thread
      plugin->moveToThread(thread);
      thread->start();

      qDebug() << "Successfully loaded plugin at" << path;
   }
   else
   {
      qCritical() << "Failed to load plugin at" << path;
   }
}

void PluginManager::unloadPlugin(QString path)
{
   QPluginLoader loader(path);

   // Plugin is currently loaded
   if(loader.isLoaded())
   {
      IPlugin *interface = qobject_cast<IPlugin*>(loader.instance());
      Plugin *plugin = interface->getPlugin();
      QThread *thread = thePlugins.take(plugin);

      thread->quit();
      thread->wait();
      delete thread;

      qDebug() << "Successfully unloaded plugin at" << path;
   }
}
